package com.zh.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.constants.Constants;
import com.zh.exception.GlobalException;
import com.zh.mapper.DriverAuthMaterialMapper;
import com.zh.mapstruct.DriverStructMapper;
import com.zh.pojo.domain.Driver;
import com.zh.pojo.domain.DriverAuthMaterial;
import com.zh.pojo.dto.AuditParamDto;
import com.zh.pojo.dto.DriverAuthDto;
import com.zh.pojo.vo.DriverAuthVo;
import com.zh.remote.api.LoginApi;
import com.zh.remote.pojo.param.UpdateLoginDto;
import com.zh.service.IDriverAuthMaterialService;
import com.zh.service.IDriverMaterialAuthLogService;
import com.zh.service.IDriverService;
import com.zh.template.IDCardTemplate;
import com.zh.template.SMSTemplate;
import com.zh.utils.AssertUtil;
import com.zh.utils.BitStatesUtils;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 司机实名资料 服务实现类
 * </p>
 *
 * @author zzl
 * @since 2023-11-17
 */
@Service
@Slf4j
public class DriverAuthMaterialServiceImpl extends ServiceImpl<DriverAuthMaterialMapper, DriverAuthMaterial> implements IDriverAuthMaterialService {
    private  static final Date nowDate = new Date();

    @Autowired
    private IDCardTemplate idCardTemplate;
    @Autowired
    private IDriverService  driverService;
    @Autowired
    private IDriverMaterialAuthLogService   authLogService;
    @Autowired
    private LoginApi loginApi;
    // 发送短信
    @Autowired
    private SMSTemplate smsTemplate;

    /**
     * 撤销实名认证
     * @param auditParamDto
     */
    @Override
    @GlobalTransactional
    public void revoke(AuditParamDto auditParamDto) {
        // 1、参数判断
        AssertUtil.isNotNull(auditParamDto.getId(),"实名资料id为空");
        // 2、查询实名认证资料
        DriverAuthMaterial authMaterial = super.getById(auditParamDto.getId());
        // 3、条件判断
        AssertUtil.isNotNull(authMaterial,"实名资料不存在");
        AssertUtil.isTrue(authMaterial.getRealAuthStatus() == Constants.RealAuth.STATUS_AUDIT_SUCCESS,"非法参数");
        //*  1.参数判断，业务条件判断，不为空，状态必须是已完成实名认证
        //*  2.修改实名状态，设置审核人，审核时间，审核备注
        authMaterial.setAuditRemark(auditParamDto.getAuditRemark());
        authMaterial.setAuditUserId(StpUtil.getLoginIdAsLong());
        authMaterial.setAuditTime(nowDate);
        // 修改实名状态
        authMaterial.setRealAuthStatus(Constants.RealAuth.STATUS_WAIT_AUDIT);
        authMaterial.setUpdateTime(nowDate);

        // 4、查询司机信息 更改司机信息中的位状态
        Driver driver = driverService.getById(authMaterial.getDriverId());
        // 4.1 条件判断
        AssertUtil.isNotNull(driver,"司机信息不存在");
        //  4.2修改司机的位状态，移除： 认证成功的位状态
        driver.setBitState(BitStatesUtils.removeState(driver.getBitState(), BitStatesUtils.OP_REAL_AUTHENTICATIONED));
        driver.setUpdateTime(nowDate);

        driverService.updateById(driver);
        super.updateById(authMaterial);
        //*  3.插入一个实名审核日志，
        authLogService.create(authMaterial);
    }

    /**
     * 加载司机实名信息
     * @return
     */
    @Override
    public DriverAuthVo selectByDriverAuthMaterial() {
        //根据司机id 查询司机实名信息
        List<DriverAuthMaterial> authMaterialList = super.list(new LambdaQueryWrapper<>(DriverAuthMaterial.class).eq(DriverAuthMaterial::getDriverId, StpUtil.getLoginIdAsLong()));
        if(authMaterialList.isEmpty() ){
            return null;
        }
        // 将查询到的司机实名信息列表通过排序的方式根据创建时间 返回最近一条数据
        authMaterialList.sort(Comparator.comparing(DriverAuthMaterial::getCreateTime).reversed());
        return DriverStructMapper.INSTANCE.driverAuthMaterialConvertToDriverAuthVO(authMaterialList.get(0));
    }

    /**
     * 审核实名认证
     * @param auditParamDto
     */
    @Override
    @GlobalTransactional
    public void audit(AuditParamDto auditParamDto) {
        // 1、参数判断
        AssertUtil.isNotNull(auditParamDto.getId(),"实名资料id为空");
        AssertUtil.isNotNull(auditParamDto.getApprove(),"审核状态不能为空");
        // 2、查询实名认证资料
        DriverAuthMaterial authMaterial = super.getById(auditParamDto.getId());
        // 3、条件判断
        AssertUtil.isNotNull(authMaterial,"实名资料不存在");
        AssertUtil.isTrue(authMaterial.getRealAuthStatus() == Constants.RealAuth.STATUS_WAIT_AUDIT,"非法参数");
        // 4、查询司机信息 更改司机信息中的位状态
        Driver driver = driverService.getById(authMaterial.getDriverId());
        // 4.1 条件判断
        AssertUtil.isNotNull(driver,"司机信息不存在");
        // 4.2 修改司机 位状态  将司机的 实名认证中的状态删除
        long  bitState  = BitStatesUtils.removeState(driver.getBitState(), BitStatesUtils.OP_REAL_AUTHENTICATING);
        // 5、根据审批状态修改司机位状态
        if (auditParamDto.getApprove() == Constants.RealAuth.STATUS_PASS) {
            // 5.1 审核通过 修改认证材料 审核状态 为审核通过
            authMaterial.setRealAuthStatus(Constants.RealAuth.STATUS_AUDIT_SUCCESS);
            // 5.1.2 修改司机位状态  将司机的 实名认证中的状态 添加 完成实名
            bitState = BitStatesUtils.addState(bitState, BitStatesUtils.OP_REAL_AUTHENTICATIONED);
            driver.setBitState(bitState);
            // 5.1.3 远程调用 logIn 信息 保存姓名 TODO
            UpdateLoginDto updateLoginDto = new UpdateLoginDto();
            updateLoginDto.setId(driver.getId());
            updateLoginDto.setName(authMaterial.getName());
            loginApi.updateLogin(updateLoginDto);
        } else if (auditParamDto.getApprove() == Constants.RealAuth.STATUS_REJECT) {
            // 5.2 审核不通过 修改认证材料 审核状态 为审核驳回
            authMaterial.setRealAuthStatus(Constants.RealAuth.STATUS_AUDIT_FAIL);
        } else {
            // 非法参数
            throw new GlobalException("非法参数");
        }
        driver.setUpdateTime(nowDate);
        // 6 更新司机信息
        driverService.updateById(driver);
        log.info("获取审核人ID: {}" ,StpUtil.getLoginIdAsLong());
        authMaterial.setAuditUserId(StpUtil.getLoginIdAsLong());
        authMaterial.setAuditTime(nowDate);
        authMaterial.setUpdateTime(nowDate);
        authMaterial.setAuditRemark(auditParamDto.getAuditRemark());
        // 修改 实名认证材料
        boolean updateById = super.updateById(authMaterial);
        // 保存审核日志
        authLogService.create(authMaterial);
        if (updateById) {
            Date updateTime = authMaterial.getUpdateTime();
            String formatted = DateUtil.format(updateTime, "yyyy年MM月dd日 HH时mm分ss秒");
            // 发送短信通知
//            smsTemplate.SendSMS(authMaterial.getPhone(),authMaterial.getName(),formatted);
//            smsTemplate.SendSMS(authMaterial.getPhone());
        }else {
            throw new GlobalException("修改实名认证材料失败");
        }
    }


    /***
     *  实名认证材料申请
     * @param AuthDto 实名认证申请材料
     */
    @Override
    @GlobalTransactional
    public void realAuthApply(DriverAuthDto AuthDto) {

        // 对传递参数进行判断 如 手机号，邮箱 //TODO
        AssertUtil.isPhone(AuthDto.getPhone(), "手机号格式错误");
        AssertUtil.isEmail(AuthDto.getEmail(), "电子邮箱格式错误");
        // 获取登录会话Id
        long driverId = StpUtil.getLoginIdAsLong();
        // 通过DriverId 查询数据
        Driver driver = driverService.getById(driverId);
        // 判断司机的位状态
        AssertUtil.isFalse(BitStatesUtils.hasState(driver.getBitState(), BitStatesUtils.OP_REAL_AUTHENTICATIONED), "你已实名认证");
        AssertUtil.isFalse(BitStatesUtils.hasState(driver.getBitState(), BitStatesUtils.OP_REAL_AUTHENTICATING), "你已提交申请");
        // 不验证的时候记得注释掉，  因为要钱！！！！！！
//        try {
//            // 对身份证进行 验证 。通过调用三方接口进行验证
//            String result = idCardTemplate.postData(AuthDto.getName(), AuthDto.getIdNumber());
//            // 打印日志
//            log.info("身份验证成功 结果: + {}",result);
//        } catch (IOException e) {
//            throw new GlobalException("身份验证失败");
//        }

        // 修改司机的位状态，修改为，实名认证中
        driver.setBitState(BitStatesUtils.addState(driver.getBitState(), BitStatesUtils.OP_REAL_AUTHENTICATING));
        driver.setUpdateTime(nowDate);
        driverService.updateById(driver);

        // 保存 司机实名认证材料
        // 通过映射拷贝dto数据
        DriverAuthMaterial authMaterial = DriverStructMapper.INSTANCE.driverAuthDtoConvertDriverAuthMaterial(AuthDto);
        authMaterial.setRealAuthStatus(Constants.RealAuth.STATUS_WAIT_AUDIT);
        authMaterial.setCreateTime(nowDate);
        authMaterial.setDriverId(driverId);
        // 保存 实名认证材料
        super.save(authMaterial);

    }


}
